﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using Game.Logic.Data;
using NetFramework.HTTP;
using UnityEngine;
using UnityEngine.Networking;
using USClientKernel.Template;
using Common.Utils;

namespace Game.Logic.Manager
{
    public enum VersionItemState
    {
        Deleted,
        Identical,
        Modified,
        Added,
    }

    public struct GameVersionDiff
    {
        public string LastVersion;
        public string LastDate;
        public string LastType;
        public string CurVersion;
        public string CurDate;
        public string CurType;
        public List<List<string>> FileList;

        public List<List<string>> GetDifferences()
        {
            List<List<string>> rt = new List<List<string>>();
            foreach(List<string> item in FileList)
            {
                //if (VersionItemState.Identical.ToString() != item[5])
                //{
                    item[5] = VersionItemState.Added.ToString();
                    rt.Add(item);
                //}
            }
            return rt;
        }
    }

    public delegate void handler();

    public class GameVersionManager : Singleton<GameVersionManager>
    {
        public const string cdnUrl = "http://localhost";  // mark:临时用，后期需要换为CDN服务器返回的地址；

        public bool IsInitDown { get; private set; }
        private event handler m_handler;

        private GameVersionData m_clientVersion;
        public GameVersionData ClientVersion { get => m_clientVersion; }

        private GameVersionData m_serverVersion;
        public GameVersionData ServerVersion { get => m_serverVersion; }


        private static readonly string s_ClientVersionFile = string.Concat(Application.persistentDataPath + "/VersionInfo");
        public static string ClientVersionFile => s_ClientVersionFile;

        private static readonly string s_ServerVersionFile = string.Concat(Application.persistentDataPath + "/ServerVersionInfo");
        public static string ServerVersionFile => s_ServerVersionFile;


        private Downloader Downloader { get; set; }
        private DownloadResult DownloadResult { get; set; }


        public void InitGameVersion()
        {
            IsInitDown = false;
            if (File.Exists(ClientVersionFile))
            {
                SetClientVersion(GameVersionData.ParseFile(ClientVersionFile));
            }
            else
            {
                RestoreVersionFile();
            }
        }

        public void RestoreVersionFile()
        {
#if UNITY_ANDROID
            string url = Application.streamingAssetsPath + "/VersionInfo";
#else
            string url = "file:///" + Application.streamingAssetsPath + "/VersionInfo";
#endif
            Debug.LogFormat("RestoreVersionFile url-->{0} path-->{1}", url, ClientVersionFile);
            HTTPManager.Instance.DownloadFile(url, ClientVersionFile, OnRestoreVersionFile, null);
        }

        void OnRestoreVersionFile(UnityWebRequest _result)
        {
            if (_result.isNetworkError || _result.isHttpError)
            {
                Debug.LogFormat("Restore Version File {0} Failed", ClientVersionFile);
                return;
            }
            if (!_result.isDone)
            {
                Debug.LogFormat("Restore Version File {0} Failed", ClientVersionFile);
                return;
            }
            Debug.LogFormat("Restore Version File {0} Success", ClientVersionFile);
            SetClientVersion(GameVersionData.ParseFile(ClientVersionFile));
        }

        public void DownloadVersionFile(handler _handler)
        {
            string url = string.Concat(cdnUrl, "/OSX/AssetBundles/VersionInfo");
            HTTPManager.Instance.DownloadFile(url, ServerVersionFile, OnDownloadFile, null);

            if (null != _handler)
                m_handler = _handler;
        }

        void OnDownloadFile(UnityWebRequest _result)
        {
            if (_result.isNetworkError || _result.isHttpError)
                return;
            if (!_result.isDone)
                return;
            Debug.LogFormat("Download Version File {0} Success", ServerVersionFile);
            SetServerVersion(GameVersionData.ParseFile(ServerVersionFile));

            m_handler.Invoke();
            m_handler = null;
        }

        public GameVersionDiff? CompareVersion()
        {
            if (null == ClientVersion || null == ServerVersion)
                return null;

            GameVersionDiff rt;
            rt.LastVersion = ClientVersion.Ver;
            rt.LastDate = ClientVersion.Date;
            rt.LastType = ClientVersion.Type;
            rt.CurVersion = ServerVersion.Ver;
            rt.CurDate = ServerVersion.Date;
            rt.CurType = ServerVersion.Type;
            rt.FileList = new List<List<string>>();

            _GeneratorDiffList(
                rt.FileList,
                ClientVersion.VersionInfo["md5"].Value,
                ClientVersion.VersionInfo["size"].Value,
                ClientVersion.VersionInfo["hash"].Value,
                ClientVersion.VersionInfo["crc"].Value
            );

            _GeneratorDiffList(
                rt.FileList,
                ServerVersion.VersionInfo["md5"].Value,
                ServerVersion.VersionInfo["size"].Value,
                ServerVersion.VersionInfo["hash"].Value,
                ServerVersion.VersionInfo["crc"].Value
            );

            return rt;
        }

        private void _GeneratorDiffList(List<List<string>> _list, Dictionary<string, string> _dictMd5, Dictionary<string, string> _dictSize,
            Dictionary<string, string> _dictHash, Dictionary<string, string> _dictCrc)
        {
            bool bAdd = _list.Count > 0;
            foreach (var item in _dictMd5)
            {
                string filename = item.Key;
                string tag = null;
                List<string> record = null;
                foreach(var _item in _list)
                {
                    if (filename == _item[0])
                    {
                        record = _item;
                        tag = VersionItemState.Identical.ToString();
                        break;
                    }
                }

                if (null == record)
                {
                    record = new List<string>();
                    record.Add(filename);
                    if (bAdd)
                        tag = VersionItemState.Added.ToString();
                    else
                        tag = VersionItemState.Deleted.ToString();
                    _list.Add(record);
                }

                _dictSize.TryGetValue(item.Key, out string size);
                if (record.Count > 1)
                    record[1] = size;
                else
                    record.Add(size);

                string md5 = item.Value;
                if (record.Count > 2 && null != record[2] && md5 != record[2])
                    tag = VersionItemState.Modified.ToString();
                if(record.Count > 2)
                    record[2] = md5;
                else
                    record.Add(md5);

                _dictHash.TryGetValue(item.Key, out string hash);
                if (null == hash)
                    hash = "";
                if (record.Count > 3)
                    record[3] = hash;
                else
                    record.Add(hash);

                _dictCrc.TryGetValue(item.Key, out string crc);
                if (null == crc)
                    crc = "";
                if (record.Count > 4)
                    record[4] = crc;
                else
                    record.Add(crc);

                if (record.Count > 5)
                    record[5] = tag;
                else
                    record.Add(tag);
            }
        }


        public void SetClientVersion(GameVersionData _version)
        {
            m_clientVersion = _version;
            GameDataManager.Instance.RegisterGameData(ClientVersion);
            IsInitDown = true;
        }


        public void SetServerVersion(GameVersionData _version)
        {
            m_serverVersion = _version;
        }

        public DownloadResult SyncToLastVersion(List<List<string>> _differences)
        {
            if (null != DownloadResult && !DownloadResult.IsDone)
                return null;

            string url = string.Concat(cdnUrl, "/OSX/AssetBundles/");
            string path = Application.persistentDataPath;
            Downloader = new Downloader();

            foreach(List<string> item in _differences)
            {
                string name = item[0];
                string state = item[5];
                if (VersionItemState.Deleted.ToString() == state)
                {
                    string filePath = string.Concat(path, "/", name);
                    if (File.Exists(filePath))
                        File.Delete(filePath);
                }
                else
                {
                    string[] data = new string[4];
                    data[0] = string.Concat(url, name);
                    data[1] = string.Concat(path, "/", name);
                    data[2] = name;
                    data[3] = item[1];
                    Downloader.AddItem(data);
                }
            }

            DownloadResult = Downloader.StartAsync();
            CoroutineController.Instance.StartCoroutine(CheckDownloading());
            return DownloadResult;
        }

        public DownloadResult GetCurDownloadResult()
        {
            return DownloadResult;
        }

        public IEnumerator CheckDownloading()
        {
            if (null == DownloadResult)
                yield break;

            while(!DownloadResult.IsDone)
            {
                yield return new WaitForSeconds(1.0f);
            }

            ClientVersion.SetVersionData(ServerVersion);
            if (File.Exists(ServerVersionFile))
                File.Delete(ServerVersionFile);
            yield return null;
        }
    }
}
